#!/var/bin/env python
# -*- coding: utf-8 -*-

import sys
import time
import os
import commands
import psycopg2.extras
import logging.config
import pandas as pd
import utils
from imp import reload
from pandas.io.common import EmptyDataError

# エラーメッセージを読み込む
error_json = utils.read_json("./error.json")

# 文字コードを設定する
reload(sys)
sys.setdefaultencoding('utf-8')

# 処理区分を定義する
kbn = ["I", "U", "D", "i", "u", "d"]

# CSVファイルのパスを定義する
csv_file_path = ""

# 実テーブル名を定義する
db_table_name = None

# ワークテーブル名を定義する
tp_db_table_name = None

# エラーテーブル名を定義する
error_info_table_name = None

# 初期化
csv_file_name = None
csv_folder_name = None
setting_json = None
commit_counter_to_tempdb = None
commit_counter_to_maindb = None
work_dir = None
database = None
user = None
password = None
host = None
port = None
json_data = None
logger = None


def get_parameter():
    """
    入力パラメータを取得する

    Parameters
    ----------
    なし

    Returns
    -------
    なし
    """
    global db_table_name, tp_db_table_name, error_info_table_name, csv_file_name, csv_folder_name, setting_json, \
        commit_counter_to_tempdb, commit_counter_to_maindb, work_dir, database, user, password, host, port, json_data, logger

    logger = logging.getLogger()
    parameter_count = len(sys.argv)

    # pythonプログラム名も含めて、パラメータの数が２以上の場合
    if parameter_count >= 2:

        csv_file_name = sys.argv[1].split("/")[-1]

        try:
            # 設定ファイルを読み込む
            setting_json = utils.read_json("./setting.ini")
            # json定義を読み込む
            json_data = utils.read_json("./data.json", csv_file_name)

            # 初期化
            log_file_path = setting_json["log_file_path"] + json_data["batchId"]
            error_info_table_name = setting_json["schema"] + "." + setting_json["error_db_name"]
            commit_counter_to_tempdb = setting_json["commit_counter_to_tempdb"]
            commit_counter_to_maindb = setting_json["commit_counter_to_maindb"]
            work_dir = setting_json["work_dir"]
            database = setting_json["database"]
            user = setting_json["user"]
            password = setting_json["password"]
            host = setting_json["host"]
            port = setting_json["port"]
            db_table_name = setting_json["schema"] + "." + json_data["tableName"]
            tp_db_table_name = setting_json["schema"] + "." + json_data["tptableName"]

            # ログ出力設定を行う
            if not os.path.exists(log_file_path):
                os.makedirs(log_file_path)
            logging.config.fileConfig('./logging.conf', defaults={'logdir': log_file_path})

        except BaseException as bep:
            logger.error("%s : " + error_json["csv_file_name_error"], bep, exc_info=1)
            sys.exit(1)

        if parameter_count == 3:
            # ３番目のパラメータを日付かのチェックを行う
            if not utils.is_valid_date(sys.argv[2], "%Y%m%d"):
                logger.error(error_json["parameter_date_format_error"])
                sys.exit(1)
            # ３番目の日付パラメータより操作対象フォルダーを取得する
            csv_folder_name = sys.argv[2]
    else:
        # パラメータの数が足りない場合、エラーログを出力して、システム終了
        logger.error(error_json["parameter_format_error"])
        sys.exit(1)


def check_multi_startup():
    """
    多重起動判断する

    Parameters
    ----------
    なし

    Returns
    -------
    なし
    """
    logger.info("多重起動チェック処理が開始します。")
    # 実行start time
    check_start_time = time.time()

    comm_str = "ps -ef | grep python | grep %s | grep -v prep | wc -l" % csv_file_name.split(".")[0]
    output = commands.getoutput(comm_str)
    if int(output) > 1:
        logger.warning(error_json["multi_startup_error"])
        sys.exit(1)

    # 実行end time
    check_end_time = time.time()
    elapsed_time = check_end_time - check_start_time
    logger.info("多重起動チェック処理が終了しました。処理時間：" + str(round(elapsed_time, 2)) + "秒")


def check_work_table():
    """
    ワークテーブルチェックを行う

    Parameters
    ----------
    なし

    Returns
    -------
    なし
    """
    conn = None
    cur = None
    try:
        logger.info("ワークテーブルチェック処理が開始します。")
        # 実行start time
        check_start_time = time.time()

        # DB接続する
        conn = psycopg2.connect(database=database, user=user, password=password, host=host, port=port)
        cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)

        select_sql = """SELECT * FROM %s WHERE syori_flg = '0' """
        cur.execute(select_sql % tp_db_table_name)
        if cur.rowcount != 0:
            logger.error(error_json["undo_error"])
            os._exit(1)

        # error count
        error_sql = """SELECT COUNT(1) FROM %s WHERE batch_id = %%s"""
        cur.execute(error_sql % error_info_table_name, [json_data["batchId"]])
        error_count_result = cur.fetchone()
        logger.debug(error_count_result["count"])

        # record count
        record_sql = """SELECT COUNT(1) FROM %s"""
        cur.execute(record_sql % tp_db_table_name)
        record_count_result = cur.fetchone()
        logger.debug(record_count_result["count"])

        # TRUNCATE DB
        truncate_sql = """TRUNCATE TABLE %s"""
        cur.execute(truncate_sql % tp_db_table_name)

        # 記録数を出力
        logger.info(
            "error_count = %s, record_count = %s" % (error_count_result["count"], record_count_result["count"]))

        # batchIDによって、エラー情報をDBから削除する
        del_error_sql = """DELETE FROM %s WHERE batch_id = %%s """
        cur.execute(del_error_sql % error_info_table_name, [json_data["batchId"]])
        conn.commit()
        cur.close()
    except BaseException as bep:
        logger.error("%s : " + error_json["database_error"], bep, exc_info=1)
        cur.close()
        sys.exit(1)
    finally:
        if conn:
            cur.close()
            conn.close()
        # 実行end time
        check_end_time = time.time()
        elapsed_time = check_end_time - check_start_time
        logger.info("ワークテーブルチェック処理が終了しました。処理時間：" + str(round(elapsed_time, 2)) + "秒")


def check_csv_exist():
    """
    CSVファイルの存在確認を行う

    Parameters
    ----------
    なし

    Returns
    -------
    なし
    """
    try:
        logger.info("CSVファイル存在チェックが開始します。")
        # 実行start time
        check_start_time = time.time()
        global csv_file_path
        if csv_folder_name is not None:
            csv_file_path = utils.check_folder_is_existed((work_dir, csv_file_name, csv_folder_name))
        else:
            csv_file_path = utils.check_folder_is_existed((work_dir, csv_file_name,))
    except BaseException as bep:
        logger.warning(error_json["csv_file_exist_error"])
        sys.exit(1)
    finally:
        # 実行end time
        check_end_time = time.time()
        elapsed_time = check_end_time - check_start_time
        logger.info("CSVファイル存在チェック処理が終了しました。処理時間：" + str(round(elapsed_time, 2)) + "秒")


def read_csv_to_work_table():
    """
    ワークテーブルへのデータ取り込みを行う

    Parameters
    ----------
    なし

    Returns
    -------
    なし
    """
    logger.info("ワークテーブルへのデータ取り込み処理が開始します。")
    # 実行start time
    check_start_time = time.time()
    conn = None
    cur = None
    counter = 0
    try:
        # DB_Connection 生成
        conn = psycopg2.connect(database=database, user=user, password=password, host=host, port=port)
        cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)  # key，valueによって、データーを取得。

        insert_keys = json_data["columnName"]
        # ワークテーブル固定FLG KEYS追加
        insert_keys.insert(0, tp_db_table_name)
        insert_keys.append("csv_data")
        insert_keys.append("syori_flg")
        insert_values = []

        key_placeholder = ", %s" * (len(insert_keys) - 1)  # -1はtable_nameのplaceholderを取り下げます
        key_placeholder = key_placeholder[1:]

        value_placeholder = ", %%s" * (len(insert_keys) - 1)
        value_placeholder = value_placeholder[1:]

        reader = None
        try:
            if json_data["headFlg"] == "0":
                if json_data["separate"] == "\t":
                    reader = \
                        pd.read_table(csv_file_path, header=None, encoding=json_data["encode"], dtype="str",
                                chunksize=setting_json["chunksize"], iterator=True, keep_default_na=False, )
                else:
                    reader = \
                        pd.read_csv(csv_file_path, header=None, encoding=json_data["encode"], dtype="str",
                                chunksize=setting_json["chunksize"], iterator=True, keep_default_na=False)
                df = 1
            else:
                if json_data["separate"] == "\t":
                    reader = \
                        pd.read_table(csv_file_path, encoding=json_data["encode"], dtype="str",
                                    chunksize=setting_json["chunksize"], iterator=True, keep_default_na=False)
                else:
                    reader = \
                        pd.read_csv(csv_file_path, encoding=json_data["encode"], dtype="str",
                                    chunksize=setting_json["chunksize"], iterator=True, keep_default_na=False)
                df = 1
        except EmptyDataError:
            df = 2

        # 全件連携の場合
        if json_data["fullFetchFlg"] == "1" and df == 2:
            del_datetime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
            update_sql = """UPDATE %s SET del_flg='1', del_datetime=%%s"""
            logger.debug(del_datetime)
            cur.execute(update_sql % db_table_name, [del_datetime])
        elif json_data["fullFetchFlg"] == "0" and df == 2:
            logger.error(error_json["fullFetchFlg_error"])
        else:
            for content in reader:
                for indexs in content.index:
                    try:
                        error_msg = ""
                        all_error_mgs = ""
                        if json_data["headFlg"] == 1 and indexs == 0:
                            continue
                        row_data = content.loc[indexs].values
                        csv_data = content.loc[indexs, :]
                        for item_index in range(len(row_data)):

                            if json_data["columns"][item_index]["columnName"] == "" and (len(row_data) - 1) != item_index:
                                continue

                            if item_index == 0 and json_data["kbnFlg"] == "1":
                                insert_values.append(row_data[item_index])
                            else:
                                if json_data["columns"][item_index]["columnType"] == "VARCHAR2":

                                    if len(str(row_data[item_index])) <= int(
                                            json_data["columns"][item_index]["columnSize"]):
                                        temp_str = str(row_data[item_index])

                                        if "<BR>" in temp_str:
                                            temp_str = temp_str.replace("<BR>", "\n")
                                        insert_values.append(temp_str)

                                        if json_data["columns"][item_index]["columnName"] == "OYA_CD" and json_data[
                                            "pkChangeFlg"] == "1":
                                            select_oya_sql = """SELECT syohin_tokutei_cd FROM %s WHERE oya_cd = %%s"""
                                            cur.execute(select_oya_sql % json_data["relation"],
                                                        [str(row_data[item_index])])
                                            item_data = cur.fetchone()
                                            if cur.rowcount != 0:
                                                logger.debug(item_data["syohin_tokutei_cd"])
                                                if "syohin_tokutei_cd" not in insert_keys:
                                                    key_placeholder += ", %s"
                                                    value_placeholder += ", %%s"
                                                    insert_keys.insert(item_index + 2, "syohin_tokutei_cd")
                                                insert_values.append(item_data["syohin_tokutei_cd"])

                                            if cur.rowcount == 0:
                                                error_msg = "%s行目,%s列目 %s %s" % (
                                                    indexs + 1, item_index + 1, json_data["columns"][item_index]["columnName"], error_json["pk_data_not_found"])
                                                all_error_mgs += error_msg

                                        if json_data["columns"][item_index]["columnName"] == "WKFCODE" and json_data[
                                            "pkChangeFlg"] == "2":
                                            select_wkf_sql = """SELECT syohin_tokutei_cd, syohin_meisai_no FROM %s WHERE wkfcode = %%s """
                                            cur.execute(select_wkf_sql % json_data["relation"],
                                                        [str(row_data[item_index])])
                                            item_data = cur.fetchone()
                                            if cur.rowcount != 0:
                                                logger.debug(item_data["syohin_tokutei_cd"])
                                                logger.debug(item_data["syohin_meisai_no"])
                                                if "syohin_tokutei_cd" not in insert_keys and "syohin_meisai_no" not in insert_keys:
                                                    key_placeholder = key_placeholder + ", %s" * 2
                                                    value_placeholder = value_placeholder + ", %%s" * 2
                                                    #在庫データの場合、特殊で分岐をつけた
                                                    if json_data["tableName"] == "T_ZAIKO":
                                                        insert_keys.insert(item_index + 1, "syohin_tokutei_cd")
                                                        insert_keys.insert(item_index + 2, "syohin_meisai_no")
                                                    else:
                                                        insert_keys.insert(item_index + 2, "syohin_tokutei_cd")
                                                        insert_keys.insert(item_index + 3, "syohin_meisai_no")
                                                insert_values.append(item_data["syohin_tokutei_cd"])
                                                insert_values.append(item_data["syohin_meisai_no"])

                                            if cur.rowcount == 0:
                                                error_msg = "%s行目,%s列目 %s %s" % (
                                                    indexs + 1, item_index + 1, json_data["columns"][item_index]["columnName"], error_json["pk_data_not_found"])
                                                all_error_mgs += error_msg
                                    else:
                                        error_msg = "%s行目,%s列目 %s サイズチェックエラー" % (
                                            indexs + 1, item_index + 1, json_data["columns"][item_index]["columnName"])
                                        all_error_mgs += error_msg
                                elif json_data["columns"][item_index]["columnType"] == "TIMESTAMP":

                                    if row_data[item_index] == "" and (len(row_data) - 1) == item_index:
                                        insert_values.append(None)
                                    elif row_data[item_index] == "":
                                        insert_values.append(None)
                                        continue

                                    if len(str(row_data[item_index])) > int(
                                            json_data["columns"][item_index]["columnSize"]):
                                        error_msg = "%s行目,%s列目 %s サイズチェックエラー" % (indexs + 1, item_index + 1,
                                                                                    json_data["columns"][item_index][
                                                                                        "columnName"])
                                        all_error_mgs += error_msg
                                    else:
                                        if row_data[item_index] != "":
                                            if not utils.is_valid_date(str(row_data[item_index]),
                                                                       str(json_data["columns"][item_index]["format"])):
                                                error_msg = "%s行目,%s列目 %s データフォーマットチェックエラー(%s)" % \
                                                            (indexs + 1, item_index + 1,
                                                             json_data["columns"][item_index]["columnName"],
                                                             json_data["columns"][item_index]["format"]
                                                             )
                                                all_error_mgs += error_msg
                                    if len(str(row_data[item_index])) <= int(
                                            json_data["columns"][item_index]["columnSize"]) and utils.is_valid_date(
                                        str(row_data[item_index]), str(json_data["columns"][item_index]["format"])):
                                        temp_time = row_data[item_index]
                                        utc_time = utils.get_utctime(temp_time, json_data["columns"][item_index]["format"])
                                        logger.debug(utc_time)
                                        insert_values.append(utc_time)
                                elif json_data["columns"][item_index]["columnType"] == "NUMBER":

                                    try:
                                        float(row_data[item_index])
                                        if "." in row_data[item_index]:
                                            sup_number = str(row_data[item_index]).split(".")
                                            if len(row_data[item_index].replace('.', '')) <= int(
                                                    json_data["columns"][item_index]["columnSize"]) and len(
                                                sup_number[-1]) <= int(
                                                json_data["columns"][item_index]["scale"]):
                                                insert_values.append(row_data[item_index])
                                            else:
                                                error_msg = "%s行目,%s列目 %s サイズチェックエラー" % (indexs + 1, item_index + 1,
                                                                                        json_data["columns"][
                                                                                            item_index]["columnName"])
                                                all_error_mgs += error_msg
                                        else:
                                            if len(row_data[item_index]) <= int(
                                                    json_data["columns"][item_index]["columnSize"]):
                                                insert_values.append(row_data[item_index])
                                            else:
                                                error_msg = "%s行目,%s列目 %s サイズチェックエラー" % (indexs + 1, item_index + 1,
                                                                                        json_data["columns"][
                                                                                            item_index]["columnName"])
                                                all_error_mgs += error_msg
                                    except:
                                        error_msg = "%s行目,%s列目 %s データ型チェックエラー" % (indexs + 1, item_index + 1,
                                                                                  json_data["columns"][item_index][
                                                                                      "columnName"])
                                        all_error_mgs += error_msg

                            if error_msg != "":
                                key_info = ""
                                csv_pk_index = json_data["csv_pk_index"]
                                for index in csv_pk_index:
                                    key_info += str(row_data[index]) + ","
                                error_sql = """INSERT INTO %s (batch_id, batch_group_id, table_name, key_info, error_info, csv_row_data) \
                      VALUES (%%s, %%s, %%s, %%s, %%s, %%s)"""
                                error_value = [json_data["batchId"], json_data["batch_group_id"],
                                               db_table_name, \
                                               key_info[:-1], error_msg, ",".join(map(str, csv_data))]
                                cur.execute(error_sql % error_info_table_name, error_value)
                                logger.error(error_msg)
                                insert_values = []
                                counter = counter + 1
                                if counter % commit_counter_to_tempdb == 0:
                                    logger.debug("will commit, counter = %d" % counter)
                                    conn.commit()
                                break
                            else:
                                if (item_index == len(row_data) - 1) and all_error_mgs == "":
                                    # ワークテーブルCSV_DATA追加
                                    insert_values.append(",".join(map(str, csv_data)))
                                    # ワークテーブルSYORI_FLG追加
                                    insert_values.append('0')

                                    # データをDBに読み込み
                                    insert_sql = "INSERT INTO %s" + " (" + key_placeholder + ")" + " VALUES " \
                                                 + "(" + value_placeholder + ")"
                                    logger.debug(insert_sql % tuple(insert_keys))
                                    cur.execute(insert_sql % tuple(insert_keys), insert_values)
                                    insert_values = []
                                    counter = counter + 1
                                    if counter % commit_counter_to_tempdb == 0:
                                        logger.debug("will commit, counter = %d" % counter)
                                        conn.commit()
                    except BaseException as bep:
                        logger.error("%s : " + error_json["database_error"], bep, exc_info=1)
                        conn.commit()
                        insert_values = []
    except BaseException as bep:
        logger.error("%s : " + error_json["database_error"], bep, exc_info=1)
        cur.close()
        sys.exit(1)
    finally:
        if conn:
            logger.debug("finally commit counter = %d" % counter)
            conn.commit()
            cur.close()
            conn.close()
    # 実行end time
    check_end_time = time.time()
    elapsed_time = check_end_time - check_start_time
    logger.info("ワークテーブルへのデータ取り込み処理が終了しました。処理時間：" + str(round(elapsed_time, 2)) + "秒")


if __name__ == "__main__":

    get_parameter()

    check_multi_startup()

    check_work_table()

    check_csv_exist()

    read_csv_to_work_table()
